home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************/
- /* This file contains the datastructures used by PFS */
- /* Most structures that are not directly written to disk are apt */
- /* to change. */
- /**********************************************************************/
-
- // max lengte van filename, diskname en comment
- #define FNSIZE 108
- #define DNSIZE 32
- #define CMSIZE 80
-
- #define ID_PFS_DISK (0x50465300L) //'PFS\0'
-
- typedef unsigned char *DSTR; // lengte, dan karakters
-
- // IsDir(x) en IsFile(x) Argument: union objectinfo
- #define IsDir(oi) ((oi).file.direntry && ((oi).file.direntry->type)>0)
- #define IsFile(oi) ((oi).file.direntry && ((oi).file.direntry->type)<=0)
- #define IsVolume(oi) ((oi).volume.root==0)
- #define IsSameOI(oi1, oi2) ((oi1.file.direntry == oi2.file.direntry) && \
- (oi1.file.dirblock == oi2.file.dirblock))
-
- // IsRoot(fi) checked of *oi bij de rootdir hoort
- // IsRootA(fi) checked of oi bij de rootdir hoort
- #define IsRoot(oi) (((oi)==NULL) || ((oi)->volume.root == NULL))
- #define IsRootA(oi) ((oi).volume.root == NULL)
-
- // *lock -> *fileentry
- #define LOCKTOFILEENTRY(l) ((struct fileentry *)(((UBYTE*)l)-4))
-
- /**********************************************************************/
- /* File administration */
- /**********************************************************************/
-
- /* FileInfo
- **
- ** This are internal representations of files. A volumeinfo is recognized
- ** by a zero root field.
- **
- ** The fileinfo->direntry en fileinfo->dirblock directly point into a
- ** cached directory block. That block is guaranteed to be present.
- ** If a pointer to a objectinfo is NULL, the root of the current
- ** volume is meant.
- */
- struct fileinfo
- {
- struct direntry *direntry;
- struct cdirblock *dirblock;
- };
-
- struct volumeinfo
- {
- ULONG root; // always 0
- struct volumedata *volume;
- };
-
- union objectinfo
- {
- struct fileinfo file; // 0 =>it's a volumeinfo; <>0 => it's a fileinfo
- struct volumeinfo volume;
- };
-
- /**********************************************************************/
- /* Fileentries/locks & volumes */
- /**********************************************************************
- **
- ** Three structures with the same basis, but different length. The are
- ** all coupled with 'next'.
- ** lock->fl_Key is the directoryblocknr
- */
-
- /* entrytype's
- ** PS: ETF_VOLUME and ETF_LOCK are both LOCKS! TEST ON BOTH
- */
- #define ET_VOLUME 0x0004
- #define ET_FILEENTRY 0x0008
- #define ET_LOCK 0x000c
- #define ETF_VOLUME 1
- #define ETF_FILEENTRY 2
- #define ETF_LOCK 3
- #define ET_SHAREDREAD 0
- #define ET_SHAREDWRITE 1
- #define ET_EXCLREAD 2
- #define ET_EXCLWRITE 3
-
- #define IsVolumeEntry(e) ((e)->type.flags.type == ETF_VOLUME)
- #define IsFileEntry(e) ((e)->type.flags.type == ETF_FILEENTRY)
- #define IsLockEntry(e) ((e)->type.flags.type == ETF_LOCK)
-
- #define IsVolumeLock(le) ((le)->type.flags.type == ETF_VOLUME)
-
- #define SHAREDLOCK(t) ((t).flags.access <= 1)
-
- // ANODENR for fe's and le's; FIANODENR for fileinfo's; NOT FOR VOLUMES!!
- #define ANODENR(fe) ((fe)->info.file.direntry->anode)
- #define FIANODENR(fi) ((fi)->direntry->anode)
-
- union listtype
- {
- struct
- {
- unsigned pad:11;
- unsigned dir:1; // 0 = file; 1 = dir or volume
- unsigned type:2; // 0 = unknown; 3 = lock; 1 = volume; 2 = fileentry
- unsigned access:2; // 0 = read shared; 2 = read excl; 1,3 = write shared, excl
- } flags;
-
- UWORD value;
- };
-
- typedef union listtype listtype;
-
- /* Listentry
- **
- **- All locks on a volume are coupled from volume->firstfe by 'next'.
- ** The end of the chain is 0.
- **- [volume] points back to the volume
- **- [info] is {NULL, don't care} if root.
- */
-
- /* the general structure */
- struct listentry
- {
- struct listentry *next; // the link
- struct FileLock lock; // contains accesstype, dirblocknr
- listtype type;
- union objectinfo info; // directory reference
- struct volumedata *volume; // the volume the lock is on
- };
-
- /* the specific structures */
- struct fileentry
- {
- struct fileentry *next;
- struct FileLock lock;
- listtype type;
- union objectinfo info;
- struct volumedata *volume;
-
- UWORD currentanode; // anodenr belonging to offset in file
- UWORD anodeoffset; // blocknr within current anode
- UWORD blockoffset; // byteoffset within current block
- ULONG offset; // offset from start of file
- };
-
- struct lockentry
- {
- struct lockentry *next;
- struct FileLock lock;
- listtype type;
- union objectinfo info;
- struct volumedata *volume;
-
- UWORD nextanode; // used for examinenext
- struct fileinfo nextentry; // and examineall
- };
-
-
- /* Converts DOS BCPL Lock pointer (returned by Lock()) to a lockentry
- ** pointer
- */
- #define LockEntryFromLock(x) ((x) ? \
- (struct lockentry*)((UBYTE*)BADDR(x)-offsetof(struct lockentry, lock)) : 0)
-
- #define ListEntryFromLock(x) ((x) ? \
- (struct listentry*)((UBYTE*)BADDR(x)-offsetof(struct lockentry, lock)) : 0)
-
-
- /**********************************************************************/
- /* Disk administration */
- /**********************************************************************/
-
- struct volumedata
- {
- struct volumedata *next; // volumechain
- struct DeviceList *devlist;
- struct rootblock *rootblk;
-
- struct listentry *firstfe; // the fileentrylist
- struct canodeblock *firstanblk; // the cached anodeblocklist
- struct cdirblock *firstdirblk; // the cached dirblocklist
-
- BOOL rootblockchangeflag;
- WORD numsofterrors;
- WORD diskstate; // normally ID_VALIDATED
- LONG numblocks; // total number of blocks
- LONG numblocksused;
- LONG numblocksfree;
- WORD bytesperblock;
- };
-
- /**********************************************************************/
- /* Blockformat */
- /**********************************************************************/
-
- #define DBLKID 0x4442 //'DB'
- #define ABLKID 0x4142 //'AB'
-
-
- /* Directory blocks
- **
- ** dirblock structure:
- **
- ** This is what a dirblock looks like on disk. Reserved fields are for
- ** future extension.
- **
- ** CDirBlock structure:
- **
- ** This is how a dirblock is cached.
- **
- ** DirEntry structure:
- **
- ** The 'type', 'creationtime' and 'protection' are, except for their
- ** size, in DOS format.
- ** The filename and the comment are dynamic: size followed by that
- ** number of characters (like BSTRs). The comment directly follows the
- ** filename. The 'next' field contains the size of the direntry. This
- ** should always be even. The end of the directoryblock is marked by
- ** next = 0.
- **
- ** The size of a direntry can be calculated by:
- ** size = (sizeof(struct direntry) + strlen(name) + strlen(comment))&0xfe
- */
- #define DB_HEADSPACE (6 + 10)
- #define DB_ENTRYSPACE (TD_SECTOR - 16)
-
- struct dirblock // voor disk only (WORD blokno), timestamp later..
- {
- UWORD id; // 'DB'
- ULONG reserved_1[2];
- UWORD reserved_2;
- UWORD anodenr; // anodenr belonging to this directory (points to FIRST block of dir)
- UWORD parent; // parent; ANODE_ROOTDIR = root
- UBYTE entries[DB_ENTRYSPACE]; // entries, fini by NULL
- };
-
- struct cdirblock
- {
- struct cdirblock *next; // voor cachelist
- struct volumedata *volume;
- UWORD blocknr; // for already cached check
- UWORD usecount;
- UWORD changeflag;
- UWORD done;
- struct dirblock blk;
- };
-
- struct direntry
- {
- UBYTE next; // sizeof direntry
- BYTE type; // dir, file, link etc
- UWORD anode; // anode nummer
- ULONG size; // sizeof file
- UWORD creationday; // days since Jan. 1, 1978 (ala ADOS; WORD ipv LONG)
- UWORD creationminute; // minutes past modnight
- UWORD creationtick; // ticks past minute, not really needed
- UBYTE protection; // protection bits (ala ADOS)
- UBYTE nlength; // lenght of filename
- UBYTE startofname; // filename, followed by commentlen & comment
- UBYTE pad; // make size even
- };
-
- // comment: de is struct direntry *
- #define COMMENT(de) ((UBYTE*)(&((de)->startofname) + (de)->nlength))
- #define OBJECTNAME(de) ((UBYTE*)(&(de->startofname)))
-
- // get a pointer to the next direntry; de = struct direntry *
- #define NEXTENTRY(de) ((struct direntry*)((UBYTE*)(de) + (de)->next))
-
- // get a pointer to the firste direntry; blok is struct dirblock *
- #define FIRSTENTRY(blok) ((struct direntry*)((blok)->blk.entries))
-
- #define ENTRYLEN(de, comment) ((sizeof(struct direntry) + (de)->nlength + strlen(comment))&0xfffe)
-
-
- /* Anode blocks and Anodes
- **
- ** All space on disk is allocated by anodes. Anodes are runlength
- ** lists: a blocknr and a number indicating how many blocks are
- ** allocated by this anode.
- **
- ** The anodes are organized in an array spread over anodeblocks. The
- ** anodenr is the index in this array. The anodeblock themselves are
- ** allocated in the rootblock.
- **
- ** The first 6 anodes have a special function, they allocate
- ** freespace, the rootdirectory and perform system functions
- **
- ** Every anodeblock contains ANODESINBLOCK anodes.
- **
- ** struct canodeblock:
- **
- ** The anodeblock in the cache..
- **
- ** struct anode:
- **
- ** The anode itself. The 'clustersize' is the number of blocks being
- ** allocated. The allocated blocks are 'blocknr' up to (but not
- ** including) 'blocknr' + 'clustersize'. The 'next' field is a link
- ** to another anode where the allocation continues. At the end of the
- ** anode chain next = 0.
- **
- ** If blocknr = 0 the anode is free, and can be reused. If the anode
- ** contains { 0, -1, next} the anode is reserved by a file or
- ** directory but is not yet in use. PS: empty anodes, with clustersize
- ** 0, are valid.
- ** Vrijgeven van een anode: clustersize = 0; blocknr = 0; next = 0;
- */
-
- #define ANODESINBLOCK 82
-
- /* anode 0 is reserved; EOF; must be 0, -1, 0 (use for endoflist detection)
- ** ANODE_FREESPACE MUST have ANODE_RESERVED linked. All reserved blocks
- ** must be at the end of the chain. There may not be 'mixed' anodes
- ** anywhere
- **
- ** Anodes < 6 may be {0,0,0} but should NEVER be allocated for other
- ** purposes.
- ** ANODE_FREESPACE, ANODE_BADBLOCKS and ANODE_EOF should always be
- ** reserved {0, -1, 0}.
- ** ANODE_USERFIRST is the first anode usable for files etc.
- */
- #define ANODE_EOF 0
- #define ANODE_FREESPACE 1
- #define ANODE_RESERVED 2
- #define ANODE_TOBEFREED 3
- #define ANODE_BADBLOCKS 4
- #define ANODE_ROOTDIR 5
- #define ANODE_USERFIRST 6
-
- struct anode
- {
- UWORD clustersize;
- UWORD blocknr;
- UWORD next;
- };
-
-
- struct anodeblock
- {
- UWORD id;
- ULONG reserved_1[2];
- UWORD seqnr; // sequence number of anodeblock (starts with 0)
- UWORD next; // chain, 0 = end
- UWORD pad;
- struct anode nodes[ANODESINBLOCK];
- ULONG reserved_2;
- };
-
- struct canodeblock
- {
- struct canodeblock *next; // for cachelist
- struct volumedata *volume;
- UWORD blocknr;
- UWORD usecount;
- UWORD changeflag;
- UWORD done;
- struct anodeblock blk;
- };
-
-
- /* Data blocks
- */
- #define DATAINBLOCK 512
-
- struct datablock
- {
- UBYTE data[DATAINBLOCK]; // only data
- };
-
- /* Rootblock and bootblocks
- */
- #define BOOTBLOCK1 0
- #define BOOTBLOCK2 1
- #define ROOTBLOCK 2
-
- struct rootblock
- {
- LONG disktype; // 'FDOS' same place as AmigaDos puts id
- LONG reserved_1[2];
- UWORD creationday; // days since Jan. 1, 1978 (ala ADOS; WORD ipv LONG)
- UWORD creationminute; // minutes past midnight
- UWORD creationtick; // ticks past minute, not really needed
- UWORD protection; // protection bits (ala ADOS)
- UBYTE diskname[32]; // DSTR of diskname;
- UWORD firstreserved; // first reserved block (must be 0)
- UWORD lastreserved; // end of reserved area
- LONG reserved_2[10];
- WORD anodeblocks[42]; // 0->notallocated
- UBYTE reserved_3[DATAINBLOCK - 96 - 2*42];
- };
-
- struct bootblock
- {
- LONG disktype;
- UBYTE reserved[508];
- };
-
-
- /* Reserved areas and other notes
- **
- ** Anode and directory blocks are allocated in a special reserved area
- ** at the start of the partition. The reserved area bounderies are defined
- ** in the rootblock and vary with disksize. The reserved area can
- ** overflow in the normal area and vice versa.
- **
- ** Directories are allocated by anodes, but they don't support
- ** clustersizes other than 1.
- **
- ** Allocation strategy
- **
- ** PFS always always writes directory and anodeblocks in a different
- ** place than they came from. The same for files: overwritten files are
- ** actually written somewhere else. A kind of 'freed first reused last'
- ** (FFRL) algorithm is used, so old versions stay on the disk for a long
- ** time. Sometimes PFS will abandon FFRL if this can prevent fragmentation.
- ** Recovery tools could make use of this: old versions can be restored
- ** if the current one is corrupt, and deleted files can be recovered.
- **
- ** Update strategy
- **
- ** Dirty anode and dirblocks are written to disk before the rootblock.
- ** Because the rootblock allocates the anodeblock which allocate the
- ** directories, and every anode is written on a new position, all
- ** changes take effect at the moment the rootblock is written. Before
- ** that seemingly nothing has changed.
- */
-
-
-